#include "header.h"

pthread_mutex_t mutex1= PTHREAD_MUTEX_INITIALIZER;

void run_quicksort_multithread(int thread_no)
{
	int i;
	pthread_t* thread_id;

	thread_id =(pthread_t*)malloc(sizeof(pthread_t)*(thread_no));

	startend structure[thread_no];

	for(i=0;i<thread_no;i++)
	{
		structure[i].end = 999;
		structure[i].start = 0;
		structure[i].thread_no = thread_no;
		structure[i].thread_id = i+1;
		pthread_create(&thread_id[i],NULL, quicksort_thread, (void*) &structure[i]);
	}

	for(i=0;i<thread_no;i++)
	{
		pthread_join(thread_id[i],NULL);
	}
	free(thread_id);
}

void *quicksort_thread(void *param)
{
	startend *structure;
	structure =(startend*) param;
	int i;

	for(i=(*structure).thread_id-1;i<=(*structure).end;)
	{
		if((*structure).thread_no == 2)
			quick_sort(quick_multi_thread2,0,999,i);
		else if((*structure).thread_no == 4)
			quick_sort(quick_multi_thread4,0,999,i);
		else if((*structure).thread_no == 8)
			quick_sort(quick_multi_thread8,0,999,i);
		else if((*structure).thread_no == 16)
			quick_sort(quick_multi_thread16,0,999,i);
		else
		{
			printf("error with thread amount for quicksort!\n");
			exit(1);
		}
		i=i+(*structure).thread_no;
	}
	pthread_exit(0);
}


void *custom_merge(void* param)
{	//Merges by calling merge_arrays() function... function to be called from thread.
	custom *pack;
	int** temp;

	pack = (custom*) param;

	if((*pack).thread_no==2)
		temp = merge2;
	else if((*pack).thread_no==4)
		temp = merge4;
	else if((*pack).thread_no==8)
		temp = merge8;
	else if((*pack).thread_no==16)
		temp = merge16;

	temp[(*pack).result] = merge_arrays(temp[(*pack).first], temp[(*pack).second], size[(*pack).first], size[(*pack).second]);
}

void *mergesort_thread(void *param)
{
	mergeStruct *structure;
	int ***arraytable;

	structure = (mergeStruct*) param;

	if((*structure).thread_no==2)
	{//Assigns proper array
		arraytable = &merge2;
	}
	else if((*structure).thread_no==4)
	{
		arraytable = &merge4;
	}
	else if((*structure).thread_no==8)
	{
		arraytable = &merge8;
	}
	else if((*structure).thread_no==16)
	{
		arraytable = &merge16;
	}

//	pthread_mutex_lock(&mutex1);	//Locks for the whole cycle.... This is a problem... But the results are same whether or not they are turned on or off
	merge_thread(quick_multi_thread2,arraytable,(*structure).start, (*structure).end, 1024/(*structure).thread_no);
//	pthread_mutex_unlock(&mutex1);

	pthread_exit(0);
}
int** run_mergesort_multithread(int thread_no)
{
	int i, temp=0;
	pthread_t* thread_id;
	mergeStruct* structure;

	thread_id =(pthread_t*)malloc(sizeof(pthread_t)*(thread_no));
	structure = (mergeStruct*)malloc(sizeof(mergeStruct)*(thread_no));
	for(i=0;i<thread_no;i++)
	{

		structure[i].end = temp+1023/thread_no;
		structure[i].start = temp;
		structure[i].thread_no = thread_no;
		structure[i].thread_id = i+1;
		pthread_create(&thread_id[i],NULL, mergesort_thread, (void*) &structure[i]);
		temp = structure[i].end +1;
	}

	for(i=0;i<thread_no;i++)
	{

		pthread_join(thread_id[i],NULL);

	}

	if(thread_no==2)
	{//Merge Once

		merge2[1022] = merge_arrays(merge2[1020],merge2[1021],size[1020],size[1021]);

	}
	else if(thread_no==4)
	{//Merge 3 times
		//fprintf(stderr,"Thread 4?\n");

		merge4[1020] = merge_arrays(merge4[1016], merge4[1017], size[1016], size[1017]);
		merge4[1021] = merge_arrays(merge4[1018], merge4[1019], size[1018], size[1019]);
		merge4[1022] = merge_arrays(merge4[1020], merge4[1021], size[1020], size[1021]);
	}
	else if(thread_no==8)
	{//Merge 7 times
		//fprintf(stderr,"Thread 8?\n");
		merge8[1016] = merge_arrays(merge8[1008], merge8[1009], size[1008], size[1009]);
		merge8[1017] = merge_arrays(merge8[1010], merge8[1011], size[1010], size[1011]);
		merge8[1018] = merge_arrays(merge8[1012], merge8[1013], size[1012], size[1013]);
		merge8[1019] = merge_arrays(merge8[1014], merge8[1015], size[1014], size[1015]);

		merge8[1020] = merge_arrays(merge8[1016], merge8[1017], size[1016], size[1017]);
		merge8[1021] = merge_arrays(merge8[1018], merge8[1019], size[1018], size[1019]);
		merge8[1022] = merge_arrays(merge8[1020], merge8[1021], size[1020], size[1021]);
	}
	else if(thread_no==16)
	{//Merge 15 times
		//fprintf(stderr,"Thread 16?\n");
		merge16[1008] = merge_arrays(merge16[992], merge16[993], size[992], size[993]);
		merge16[1009] = merge_arrays(merge16[994], merge16[995], size[994], size[995]);
		merge16[1010] = merge_arrays(merge16[996], merge16[997], size[996], size[997]);
		merge16[1011] = merge_arrays(merge16[998], merge16[999], size[998], size[999]);
		merge16[1012] = merge_arrays(merge16[1000], merge16[1001], size[1000], size[1001]);
		merge16[1013] = merge_arrays(merge16[1002], merge16[1003], size[1002], size[1003]);
		merge16[1014] = merge_arrays(merge16[1004], merge16[1005], size[1004], size[1005]);
		merge16[1015] = merge_arrays(merge16[1006], merge16[1007], size[1006], size[1007]);

		merge16[1016] = merge_arrays(merge16[1008], merge16[1009], size[1008], size[1009]);
		merge16[1017] = merge_arrays(merge16[1010], merge16[1011], size[1010], size[1011]);
		merge16[1018] = merge_arrays(merge16[1012], merge16[1013], size[1012], size[1013]);
		merge16[1019] = merge_arrays(merge16[1014], merge16[1015], size[1014], size[1015]);

		merge16[1020] = merge_arrays(merge16[1016], merge16[1017], size[1016], size[1017]);
		merge16[1021] = merge_arrays(merge16[1018], merge16[1019], size[1018], size[1019]);

		merge16[1022] = merge_arrays(merge16[1020], merge16[1021], size[1020], size[1021]);
	}
	free(thread_id);
	free(structure);
	return NULL;
}
